using System;
using System.Linq;
using System.Reflection;

namespace Rosetta.Default.AddIns
{
    /// <summary>
    /// Exposes all ToXXX methods from the System.Convert class which take one type and convert to another type.
    /// </summary>
    public sealed class TypeConverter : Converter
    {
        #region Constructors

        public TypeConverter()
            : base("Type Converter")
        {
            var convertType = typeof(Convert);
            var funcType = typeof(Func<,>);
            var genericAddMethod = typeof(Converter).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).Where(m => m.Name == "Add").First();

            foreach (var method in convertType.GetMethods().Where(m => m.Name.StartsWith("To")))
            {
                var parameters = method.GetParameters();
                if (parameters.Length == 1)
                {
                    // Found ToXXX method with one parameter
                    var parameterType = parameters[0].ParameterType;
                    var returnType = method.ReturnType;

                    // Make sure it isn't object or the same type
                    if (parameterType != typeof(object) && parameterType != returnType && !parameterType.IsArray)
                    {
                        var methodName = parameterType.Name + method.Name;
                        var handlerType = funcType.MakeGenericType(parameterType, returnType);
                        var handler = Delegate.CreateDelegate(handlerType, method);

                        // Add handler
                        genericAddMethod.MakeGenericMethod(parameterType, returnType).Invoke(this, new object[] { methodName, handler, null });
                    }
                }
            }
        }

        #endregion
    }
}